package com.lanswon.qzsmk.annotation;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;

import com.lanswon.qzsmk.exception.InventoryException;
import com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException;

@Aspect
@Component
public class SystemLogAspect {
	 // 本地异常日志记录对象
 private  static  final Logger logger = LoggerFactory.getLogger(SystemLogAspect. class);
	 
     @Pointcut("@annotation(com.lanswon.qzsmk.annotation.SystemServiceLog)")  
     	public  void serviceAspect() {  
     }  
     
     @Pointcut("@annotation(com.lanswon.qzsmk.annotation.SystemControllerLog)")  
     	public  void controllerAspect() {  
     }  
     
     @Before("controllerAspect()")
     public  void doBefore(JoinPoint joinPoint) throws Exception { 
    	 //logger.info("======controller前置通知开始=====");
    	 logger.info("请求方法:" + joinPoint.getTarget().getClass().getName());
    	 logger.info("========="+joinPoint.getSignature().getName()+"方法开始========");
    	 logger.info("方法描述:" + getControllerMethodDescription(joinPoint));
    	// logger.info("=====SysLogAspect前置通知结束=====");
     }
     @After(value = "controllerAspect()")
     public void doAfter(JoinPoint joinPoint)
     {
    	 logger.info("========="+joinPoint.getSignature().getName()+"方法结束=====");
     }
     
     
     @Before("serviceAspect()")
     public  void doBefore1(JoinPoint joinPoint) throws Exception { 
    	 //logger.info("======service前置通知开始=====");
    	 logger.info("请求方法:" + joinPoint.getTarget().getClass().getName() );
    	 logger.info("========="+joinPoint.getSignature().getName()+"方法开始========");
    	 logger.info("方法描述:" + getServiceMthodDescription(joinPoint));
		
     }
     @After(value = "serviceAspect()")
     public void doAfter1(JoinPoint joinPoint)
     {
    	 logger.info("========="+joinPoint.getSignature().getName()+"方法结束=====");
     }
     public  static String getServiceMthodDescription(JoinPoint joinPoint)  
             throws Exception {  
        String targetName = joinPoint.getTarget().getClass().getName();  
        String methodName = joinPoint.getSignature().getName();  
        Object[] arguments = joinPoint.getArgs();  
        Class targetClass = Class.forName(targetName);  
        Method[] methods = targetClass.getMethods();  
        String description = "";  
         for (Method method : methods) {  
             if (method.getName().equals(methodName)) {  
                Class[] clazzs = method.getParameterTypes();  
                 if (clazzs.length == arguments.length) {  
                    description = method.getAnnotation(SystemServiceLog. class).description();  
                     break;  
                }  
            }  
        }  
         return description;  
    } 
     
    /**
     * AOP异常管理
     * @param point
     * @param e
     */
 	/*@AfterThrowing(value = "controllerAspect()", throwing = "e")
 	public Map<String, Object> doAfterThrowing(JoinPoint point, Throwable e) {
 		Map<String, Object> map = new HashMap<String, Object>();
 		String targetName = point.getTarget().getClass().getName();
 		logger.error(targetName+"发生错误==>"+e.getMessage());
 		map.put("errorMsg", e.getMessage());
		map.put("statusCode", "300");
		return map; 		
 	}*/
     
     /**
      * AOP异常处理
      * @param proceedingJoinPoint
      * @return
      * @throws Throwable
      */
     @Around("controllerAspect()")
     public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    	 Map<String, Object> map = new HashMap<String, Object>();
    	 String targetName = proceedingJoinPoint.getTarget().getClass().getName();
    	 Object result = null;
         try {
             result = proceedingJoinPoint.proceed();
         } catch (Exception e) {
        	 e.printStackTrace();
             if (e instanceof InventoryException) {
            	logger.error(targetName+"==>"+e.toString());
            	e.printStackTrace();
     			map.put("message", e.getMessage());
     			map.put("statusCode", "300");
     			return map;
             } else if(e.getCause() instanceof MySQLNonTransientConnectionException){
            	logger.error(targetName+"==>"+"数据库连接异常，请联系维护人员！");
            	e.printStackTrace();
       			map.put("message", "数据库连接异常，请联系维护人员！");
       			map.put("statusCode", "300");
       			return map;
             } else if(e instanceof DataAccessException) {
            	logger.error(targetName+"==>"+"数据库操作异常，请联系维护人员！");
            	e.printStackTrace();
      			map.put("message", "数据库操作异常，请联系维护人员！");
      			map.put("statusCode", "300");
      			return map;
             }  else{            	
            	logger.error(targetName+"==>"+"系统未知系统，请联系维护人员！");
             	e.printStackTrace();
      			map.put("message", "系统未知系统，请联系维护人员！");
       			map.put("statusCode", "300");
       			return map;
             }     
     }
         return result;
     }
     
    // 通过反射获取参入的参数
    public static String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        String description = "";

        Method[] methods = targetClass.getMethods();
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();

                if (clazzs.length == arguments.length) {
                    description = method.getAnnotation(SystemControllerLog.class).description();
                    break;
                }
            }
        }
        return description;
    }
}
